package com.budwk.app.sqfw.services.datamange.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.budwk.app.common.config.AppException;
import com.budwk.app.sqfw.dto.onlineExcel.SqfwExcelOnlineAllDTO;
import com.budwk.app.sqfw.dto.onlineExcel.SqfwFormSummaryOnlineDTO;
import com.budwk.app.sqfw.models.*;
import com.budwk.app.sqfw.services.SqfwFormsummaryNewService;
import com.budwk.app.sqfw.services.datamange.DataMangeCityCheckService;
import com.budwk.app.sqfw.services.datamange.DataMangeCityService;
import com.budwk.app.sqfw.services.datamange.DataMangeCommunityService;
import com.budwk.app.sqfw.utils.CommunityDataCleanUtils;
import com.budwk.app.sqfw.vo.SqfwDataMangeCheckVO;
import com.budwk.app.sqfw.vo.SqfwDataMangeVO;
import com.budwk.app.sys.models.Sys_user;
import com.budwk.app.sys.services.SysUserService;
import com.budwk.app.util.ThreadPoolExecutorUtil;
import com.budwk.app.util.adminUtils.CommonCheckUtils;
import com.budwk.starter.common.page.Pagination;
import com.budwk.starter.common.result.ResultCode;
import com.budwk.starter.database.service.BaseServiceImpl;
import com.budwk.starter.security.utils.SecurityUtil;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.sql.Criteria;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.random.R;
import org.nutz.plugins.wkcache.annotation.CacheRemove;

import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
@IocBean(args = {"refer:dao"})
public class DataMangeCityCheckServiceImpl extends BaseServiceImpl<Sqfw_datamange_city_check> implements DataMangeCityCheckService {
    public DataMangeCityCheckServiceImpl(Dao dao) {
        super(dao);
    }

    @Inject
    private SysUserService sysUserService;

    @Inject
    private SqfwFormsummaryNewService sqfwFormsummaryNewService;

    @Inject
    private DataMangeCommunityService dataMangeCommunityService;

    @Inject
    private DataMangeCityService dataMangeCityService;

    @Override
    public Pagination page(SqfwDataMangeCheckVO bean) {
        if (null == bean) {
            bean = new SqfwDataMangeCheckVO();
        }
        long startTime = System.currentTimeMillis();
        // 构造查询条件
        List<Sqfw_datamange_city_check> sqfwFormSummaryOnlines = new ArrayList<>();
        // 查询header头
        Cnd cnd = Cnd.NEW();
        cnd.and(Sqfw_datamange_city_check::getType, "=", bean.getType());
        cnd.and(Sqfw_datamange_city_check::getExcelSeg, "=", "header");
        List<Sqfw_datamange_city_check> sqfwFormSummaryOnlines1 = query(cnd);
        if (sqfwFormSummaryOnlines1.size() <= 0) {
            return new Pagination();
        }
        Sqfw_datamange_city_check sqfwFormSummaryOnline = sqfwFormSummaryOnlines1.get(0);
        sqfwFormSummaryOnlines.add(sqfwFormSummaryOnline);
        Criteria sql = buildQuery(bean);
        Pagination pagination = this.listPage(bean.getPageNo(), bean.getPageSize(), sql);
        List<Sqfw_datamange_city_check> sqfwOnlines = pagination.getList(Sqfw_datamange_city_check.class);
        sqfwOnlines.forEach(sqfwFormSummaryOnline1 -> {
            sqfwFormSummaryOnlines.add(sqfwFormSummaryOnline1);
        });
        pagination.setList(sqfwFormSummaryOnlines);
        log.info("DataMangeStreetCheckServiceImpl-list-耗时: {}ms", System.currentTimeMillis() - startTime);
        return pagination;
    }

    @Override
    public SqfwDataMangeCheckVO check(SqfwDataMangeCheckVO bean) {
        return null;
    }

    @Override
    @Aop(TransAop.READ_COMMITTED)
    public void report(SqfwDataMangeCheckVO bean) {
        if (null == bean) {
            throw new AppException(ResultCode.PARAM_ERROR.getMsg());
        }
        if (StringUtils.isEmpty(bean.getSqfwSummaryId())) {
            throw new AppException(ResultCode.PARAM_ERROR.getMsg());
        }
        Sqfw_datamange_city_check sqfwDatamangeCityCheck = new Sqfw_datamange_city_check();
        BeanUtil.copyProperties(bean, sqfwDatamangeCityCheck);
        Sys_user sysUser = sysUserService.fetch(SecurityUtil.getUserId());
        sqfwDatamangeCityCheck
                .setSqfwSummaryId(bean.getSqfwSummaryId())
                .setProvince(sysUser.getProvince())
                .setCity(sysUser.getCity())
                .setDistrict(sysUser.getDistrict())
                .setCounty(sysUser.getCounty())
                .setCommunity(sysUser.getCommunity())
                .setCreateBy(sysUser.getId())
                .setCreateUserName(sysUser.getUsername())
                .setDelFlag(false)
                .setUnitId(sysUser.getUnitId())
                .setUnitName(sysUser.getUnitName())
                .setType(bean.getType())
                .setExcelData(CommunityDataCleanUtils.filtJsonArraySubData(bean.getExcelData(), "_time"))
                .setCreateDate(new Date());
        if (StringUtils.isNotEmpty(sqfwDatamangeCityCheck.getExcelData())) {
            JSONArray jsonArray = JSONUtil.parseArray(sqfwDatamangeCityCheck.getExcelData());
            sqfwDatamangeCityCheck.setRowNum(String.valueOf(jsonArray.size() - 1));
        }
        insert(sqfwDatamangeCityCheck);

        // 插入上一级主表， 更新原表审核上报状态
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        try {
            CompletableFuture.runAsync(() -> {
                Sqfw_datamange_city sqfwDatamangeCity = new Sqfw_datamange_city();
                BeanUtil.copyProperties(sqfwDatamangeCityCheck, sqfwDatamangeCity);
                String excelData = sqfwDatamangeCity.getExcelData().replaceAll("#595FE0", "#FFFFFF").replaceAll("#FFFAFA", "#000000");

                // 查询详情,如果有记录则更新，否则插入新纪录
                SqfwDataMangeVO sqfwDataMangeVO = new SqfwDataMangeVO();
                sqfwDataMangeVO.setSqfwSummaryId(bean.getSqfwSummaryId());
                Sqfw_datamange_city sqfwDatamangeCityDetail = dataMangeCityService.fetch(Cnd.where("sqfw_summary_id", "=", bean.getSqfwSummaryId()));
                if (null != sqfwDatamangeCityDetail) {
                    dataMangeCityService.update(Chain.make("excel_data", excelData), Cnd.where("sqfw_summary_id", "=", bean.getSqfwSummaryId()));
                } else {
                    sqfwDatamangeCity
                            .setSqfwSummaryId(bean.getSqfwSummaryId())
                            .setProvince(sysUser.getProvince())
                            .setCity(sysUser.getCity())
                            .setDistrict(sysUser.getDistrict())
                            .setCounty(sysUser.getCounty())
                            .setCommunity(sysUser.getCommunity())
                            .setCreateBy(sysUser.getId())
                            .setCreateUserName(sysUser.getUsername())
                            .setDelFlag(false)
                            .setUnitId(sysUser.getUnitId())
                            .setUnitName(sysUser.getUnitName())
                            .setType(bean.getType())
                            .setCreateDate(new Date());
                    sqfwDatamangeCity.setExcelData(sqfwDatamangeCity.getExcelData().replaceAll("#595FE0", "#FFFFFF").replaceAll("#FFFAFA", "#000000"));
                    batchParseExcelJsonInsert(sqfwDatamangeCity);
                }
            }, executorService);
        } catch (Exception ex) {
            log.error(ex.getMessage());
        } finally {
            executorService.shutdown();
        }
    }

    /**
     * 批量插入excel解析后的数据到主表
     *
     * @param sqfwDatamangeCity
     */
    private void batchParseExcelJsonInsert(Sqfw_datamange_city sqfwDatamangeCity) {
        if (null == sqfwDatamangeCity) {
            throw new AppException(ResultCode.NULL_DATA_ERROR.getMsg());
        }
        String excelData = sqfwDatamangeCity.getExcelData();
        Sqfw_datamange_city sqfwDatamangeCity1 = dataMangeCityService.fetch(Cnd.where("type", "=", sqfwDatamangeCity.getType()).limit(1));
        try {
            JSONArray jsonArray = JSONUtil.parseArray(excelData);
            for (int i = 0; i < jsonArray.size(); i++) {
                if (ObjectUtils.isNotEmpty(sqfwDatamangeCity1) && (0 == i)) {
                    continue;
                }
                Sqfw_datamange_district sqfwDatamangeDistrictNew = new Sqfw_datamange_district();
                BeanUtil.copyProperties(sqfwDatamangeCity, sqfwDatamangeDistrictNew);
                Map<String, Map<String, String>> resultMap = new HashMap<String, Map<String, String>>();
                String excelDataNew = CommunityDataCleanUtils.parseExcelJsonForMainTable(jsonArray.get(i).toString(), resultMap);
                sqfwDatamangeDistrictNew.setExcelData(JSONUtil.toJsonStr(excelDataNew));
                sqfwDatamangeDistrictNew.setExcelSeg("body");
                if (0 == i) {
                    sqfwDatamangeDistrictNew.setExcelSeg("header");
                }
                dataMangeCityService.insert(sqfwDatamangeDistrictNew);
            }
        } catch (Exception ex) {
            log.error("市to省主表解析json异常, {}" + excelData);
        }
    }

    private void communityDataCheckByType(List<String> ids, String type) {
        if (ObjectUtils.isEmpty(ids) || StringUtils.isEmpty(type)) {
            throw new AppException(ResultCode.PARAM_ERROR.getMsg());
        }
        List<Sqfw_formSummary_new> sqfwFormSummaryNewList = sqfwFormsummaryNewService.query(Cnd.where("id", "IN", ids));
        // 获取所有相关数据字段
        String configJson = CommunityDataCleanUtils.queryDictFieldInfoByType(type);
        if (StringUtils.isEmpty(configJson)) {
            log.info("===============未查询到对应的数据字典field type===============");
            return;
        }
        LinkedHashMap<String, String> fieldMap = new LinkedHashMap<>();
        CommunityDataCleanUtils.parseDictFeild(configJson, fieldMap);

        List<SqfwFormSummaryOnlineDTO> onlineList = Collections.synchronizedList(new ArrayList<SqfwFormSummaryOnlineDTO>());

        // 检查是 该类型是否有对应的excel头,没有才插入
        List<Sqfw_datamange_community> sqfwFormSummaryOnline = dataMangeCommunityService.query(Cnd.where(Sqfw_datamange_community::getType, "=", type));
        if (sqfwFormSummaryOnline.size() <= 0) {
            SqfwFormSummaryOnlineDTO sqfwFormSummaryOnlineDTO = new SqfwFormSummaryOnlineDTO();
            sqfwFormSummaryOnlineDTO.setExcelDataMap(fieldMap);
            onlineList.add(sqfwFormSummaryOnlineDTO);
        } else {
            // to do 检查是否有新增列，更新旧数据
        }

        // 清洗param_data数据
        CommunityDataCleanUtils.cleanParamData(sqfwFormSummaryNewList, onlineList, fieldMap);

        // 组装excel数据,需要排序，所以插入表操作分开写
        List<Sqfw_datamange_community> sqfwFormSummaryOnlines = Collections.synchronizedList(new ArrayList<Sqfw_datamange_community>());
        buildExcelData(onlineList, sqfwFormSummaryOnlines, type);

        // 插入表
        Sys_user sysUser = sysUserService.fetch(SecurityUtil.getUserId());
        Sqfw_datamange_street_check sqfwDatamangeStreetCheck = new Sqfw_datamange_street_check();
        sqfwDatamangeStreetCheck
                .setProvince(sysUser.getProvince())
                .setCity(sysUser.getCity())
                .setDistrict(sysUser.getDistrict())
                .setCounty(sysUser.getCounty())
                .setCommunity(sysUser.getCommunity())
                .setCreateBy(sysUser.getId())
                .setCreateUserName(sysUser.getUsername())
                .setDelFlag(false)
                .setUnitId(sysUser.getUnitId())
                .setUnitName(sysUser.getUnitName())
                .setType(type);
        StringBuffer sb = new StringBuffer();
        sqfwFormSummaryOnlines.forEach(sqfwDatamangeCommunity -> {
            sb.append(sqfwDatamangeCommunity.getExcelData()).append(",");
        });
        String excelDataAll = "[" + sb.substring(0, sb.lastIndexOf(",")) + "]";
        sqfwDatamangeStreetCheck.setExcelData(JSONUtil.toJsonStr(excelDataAll));
        insert(sqfwDatamangeStreetCheck);

        // 更新状态为已上报
        sqfwFormsummaryNewService.update(Chain.make("audit_status", "1"), Cnd.where(Sqfw_formSummary_new::getId, "IN", ids));
    }

    /**
     * 组件excel数据,并插入数据库
     */
    private void buildExcelData(List<SqfwFormSummaryOnlineDTO> onlineList, List<Sqfw_datamange_community> sqfwFormSummaryOnlines, String type) {
        String commonId = R.UU32();
        ThreadPoolExecutor threadPoolExecutor = ThreadPoolExecutorUtil.getInstance();
        CompletableFuture[] cf = onlineList.stream().map(item -> CompletableFuture.runAsync(() ->
                        processExcelData(item, sqfwFormSummaryOnlines, commonId, type), threadPoolExecutor)
                .thenApplyAsync(r -> r)).toArray(CompletableFuture[]::new);
        CompletableFuture.allOf(cf).join();
        log.info("===========================组装Excel报文完成：{}条===========================", sqfwFormSummaryOnlines.size());
       /* onlineList.forEach(item->{
            processExcelData(item, rowCount, numCount, commonId, sqfwOnlineService);
        });*/
    }

    /**
     * 处理excel数据
     */
    private void processExcelData(SqfwFormSummaryOnlineDTO sqfwFormSummaryOnlineDTO, List<Sqfw_datamange_community> sqfwFormSummaryOnlines,
                                  String commonId, String type) {
        //synchronized (LOCK) {
        List<SqfwExcelOnlineAllDTO> sqfwExcelOnlineAllDTOS = Collections.synchronizedList(new ArrayList<SqfwExcelOnlineAllDTO>());
        String updateDate = CommunityDataCleanUtils.formatDate(String.valueOf(sqfwFormSummaryOnlineDTO.getCreateDate()));
        AtomicInteger colCount = new AtomicInteger(0);
        for (ConcurrentSkipListMap.Entry<String, String> entry : sqfwFormSummaryOnlineDTO.getExcelDataMap().entrySet()) {
            // 解析到excelJson
            SqfwExcelOnlineAllDTO sqfwExcelOnlineAllDTO = new SqfwExcelOnlineAllDTO();
            sqfwExcelOnlineAllDTO = CommunityDataCleanUtils.parseSummaryData(entry, updateDate);
            sqfwExcelOnlineAllDTOS.add(sqfwExcelOnlineAllDTO);
            sqfwFormSummaryOnlineDTO.setExcelData(JSONUtil.toJsonStr(sqfwExcelOnlineAllDTOS));
            colCount.getAndIncrement();
        }
        sqfwFormSummaryOnlineDTO.setColNum(String.valueOf(colCount.get()));
        log.info("============id:{}, 总列数：{}============", sqfwFormSummaryOnlineDTO.getSqfwSummaryId(), colCount.getAndIncrement());
        sqfwFormSummaryOnlineDTO.setCommonId(commonId);
        sqfwFormSummaryOnlineDTO.setId(R.UU32());
        sqfwFormSummaryOnlineDTO.setDelFlag(false);
        sqfwFormSummaryOnlineDTO.setSqfwSummaryId(sqfwFormSummaryOnlineDTO.getSqfwSummaryId());
        if (StringUtils.isEmpty(sqfwFormSummaryOnlineDTO.getSqfwSummaryId())) {
            sqfwFormSummaryOnlineDTO.setExcelSeg("header");
        } else {
            sqfwFormSummaryOnlineDTO.setExcelSeg("body");
        }
        if (StringUtils.isNotEmpty(type)) {
            sqfwFormSummaryOnlineDTO.setType(type);
        }
        sqfwFormSummaryOnlines.add(sqfwFormSummaryOnlineDTO);
        //}
    }

    /**
     * 将清洗好的Excel数据插入数据库
     */
    @Aop(TransAop.READ_COMMITTED)
    @CacheRemove
    private void excelDataBatchInsert(List<Sqfw_datamange_community> onlineList) {
        ThreadPoolExecutor threadPoolExecutor = ThreadPoolExecutorUtil.getInstance();
        CompletableFuture[] cf = onlineList.stream().map(item -> CompletableFuture.runAsync(() ->
                        this.insert(item), threadPoolExecutor)
                .thenApplyAsync(r -> r)).toArray(CompletableFuture[]::new);
        CompletableFuture.allOf(cf).join();
    }

    /**
     * 构造查询条件
     *
     * @param bean
     * @return
     */
    private Criteria buildQueryCond(SqfwDataMangeCheckVO bean) {
        Criteria cri = Cnd.cri();
        SqlExpressionGroup criSql = cri.where();
        // 不查询excel头
        criSql.andNotEquals(Sqfw_datamange_community::getExcelSeg, "header");
        criSql.andEquals(Sqfw_datamange_community::getDelFlag, false);
        if (null != bean && StringUtils.isNotEmpty(bean.getPlaceType())) {
            criSql.andLike("param_data->>'placeType'", bean.getPlaceType());
        }
        if (null != bean && StringUtils.isNotEmpty(bean.getCommunity())) {
            criSql.andLike(Sqfw_datamange_community::getCommunity, bean.getCommunity());
        }
        return cri;
    }

    private Criteria buildQuery(SqfwDataMangeCheckVO bean) {
        Criteria cri = Cnd.cri();
        SqlExpressionGroup criSql = cri.where();
        // 区域5级检查
        CommonCheckUtils.checkAreaRange(criSql);

        // 不查询excel头
        criSql.andNotEquals(Sqfw_datamange_community::getExcelSeg, "header");
        criSql.andEquals(Sqfw_datamange_community::getDelFlag, false);

        if (null != bean && StringUtils.isNotEmpty(bean.getQueryCondition())) {
            SqlExpressionGroup placeName = Cnd.exps("excel_data->>'placeName'", "like", "%" + bean.getQueryCondition() + "%");
            SqlExpressionGroup businessLicenseName = Cnd.exps("excel_data->>'businessLicenseName'", "like", "%" + bean.getQueryCondition() + "%");
            SqlExpressionGroup socialCreditCode = Cnd.exps("excel_data->>'socialCreditCode'", "like", "%" + bean.getQueryCondition() + "%");
            SqlExpressionGroup location = Cnd.exps("excel_data->>'location'", "like", "%" + bean.getQueryCondition() + "%");
            SqlExpressionGroup address = Cnd.exps("excel_data->>'address'", "like", "%" + bean.getQueryCondition() + "%");
            SqlExpressionGroup operator = Cnd.exps("excel_data->>'operator'", "like", "%" + bean.getQueryCondition() + "%");
            SqlExpressionGroup operatorPhone = Cnd.exps("excel_data->>'operatorPhone'", "like", "%" + bean.getQueryCondition() + "%");
            SqlExpressionGroup placeArea = Cnd.exps("excel_data->>'placeArea'", "like", "%" + bean.getQueryCondition() + "%");
            criSql.and(placeName
                    .or(businessLicenseName)
                    .or(socialCreditCode)
                    .or(location)
                    .or(address)
                    .or(operator)
                    .or(operatorPhone)
                    .or(placeArea));
        }
        return cri;
    }
}
